#ifndef RBT_PROFILE_INCLUDE
#define RBT_PROFILE_INCLUDE

#include "Object.h"
#include "Parser.h"
#include "../Stream/FileStream.h"
#include "../Stream/TextReader.h"

RETURNCODE E_QUERY_OBJECT_KEY = -1000;
RETURNCODE E_QUERY_NAME_ERROR = -1001;
RETURNCODE E_QUERY_NO_OBJECT  = -1003;
RETURNCODE E_ARGUMENT_NULL    =  1004;

class Profile
{
	typedef ObjectDirectory::iterator iterator;
	typedef KeyValue::Values KeyValueItem;
	typedef KeyValueItem::const_iterator kv_iterator;
	public:
	enum PROFILE_STATUS
	{
		STATUS_GOOD,
		STATUS_BAD
	};

	int32           m_status;
	ObjectDirectory m_objects;
public:

	void SetStatus( int32 code )
	{
		if( code != R_SUCCEED )
			m_status = STATUS_BAD;
	}

	class ObjectWapper
	{
	public:
		Profile& m_profile;
		Object & m_object;

		void SetStatus( int32 code ) const
		{
			m_profile.SetStatus( code );
		}

		template< class T >
		T GetValue() const
		{
			T value = 0;
			SetStatus( m_object.GetValue(value) );
			return value;
		}

		int32 ToString(string& value)
		{
			int32  code  = R_SUCCEED;
			switch( m_object.GetType() )
			{
			case OBJECT_INT32:
				code = Convert::ToString( (int32)*this  , value );
				break;
			case OBJECT_UINT32:
				code = Convert::ToString( (uint32)*this , value );
				break;
			case OBJECT_INT64:
				code = Convert::ToString( (int64)*this , value );
				break;
			case OBJECT_UINT64:
				code = Convert::ToString( (uint64)*this , value );
			case OBJECT_FLOAT64:
				code = Convert::ToString( (float64)*this , value );
				break;
			case OBJECT_STRING:
				code = m_object.GetValue( value );
				break;
			case OBJECT_KEYVALUE:
				{
					KeyValue* keyValue = 0;
					m_object.GetValue( keyValue );
					code = ToString( keyValue , value );
					break;
				}
			case OBJECT_UNINIT:
				{
					value = _RBT("Uninitalize");
					code = R_SUCCEED;
					break;
				}
			}
			return R_SUCCEED;
		}


// 		int32 ToString( Array* vArray , string& value )
// 		{
// 			value.clear();
// 			int32 code = R_SUCCEED;
// 
// 			Array::iterator first = vArray->begin();
// 			Array::iterator last  = vArray->end();
// 
// 			value.append( _RBT("[") );
// 			for(;first!=last;++first)
// 			{
// 				string vString;
// 				code = ToString(  )
// 			}
// 		}

		int32 ToString( KeyValue* keyValue , string& value )
		{
			value.clear();
			int32 code = R_SUCCEED;

			KeyValue::iterator first = keyValue->begin();
			KeyValue::iterator last  = keyValue->end();

			value.append(_RBT("{"));
			for(;first!=last;++first)
			{
				ObjectWapper wapper( first->second , m_profile );
				string key     = first->first;
				string vString;
				code = wapper.ToString( vString );
				if( code != R_SUCCEED )
					return code;

				value.append(key);
				value.append(_RBT("="));
				value.append(vString);
				value.append(_RBT(","));
			}
			
			value[value.size()-1] = _RBT('}');


		}

	public:
		ObjectWapper( Object& object , Profile& profile ) 
			: m_object(object) , m_profile(profile)
		{	
		}

		operator int32() const
		{
			return GetValue<int32>();
		}

		operator uint32() const
		{
			return GetValue<uint32>();
		}

		operator int64() const
		{
			return GetValue<int64>();
		}

		operator uint64() const
		{
			return GetValue<uint64>();
		}

		operator float64() const
		{
			return GetValue<float64>();
		}

		operator string() const
		{
			
		}
	};
public:

	int32 QueryObjectByKey( cstring& name , Object& object )
	{
		iterator it = m_objects.find( name );
		if(it == m_objects.end())
			return E_QUERY_OBJECT_KEY;
		object = it->second;
		return R_SUCCEED;
	}

	int32 QueryObject( cstring& name , Object& object )
	{
		int32             code    = R_SUCCEED;
		string::size_type findPos = name.find(_RBT("."));

		if(findPos == string::npos)
		{
			return QueryObjectByKey(name,object);
		}
		else
		{
			string key( name.begin() , name.begin() + findPos );
			string subKey(name.begin() + findPos + 1 ,name.end());

			if(key.empty() || subKey.empty())
				return E_QUERY_NAME_ERROR;

			Object subObject;
			code = QueryObjectByKey(key,subObject);
			if( code != R_SUCCEED )
				return code;

			if( subObject.GetType() != OBJECT_KEYVALUE )
				return E_QUERY_NAME_ERROR;

			KeyValue* keyValue = 0;
			code = subObject.GetValue(keyValue);

			if(code != R_SUCCEED)
				return code;

			kv_iterator it = keyValue->m_values.find( subKey );

			if( it == keyValue->m_values.end() )
				return E_QUERY_NO_OBJECT;

			object = it->second;

			return R_SUCCEED;
		}

	}

	int32 Initialize()
	{
		return R_SUCCEED;
	}

	int32 Uninitialize()
	{
		return R_SUCCEED;
	}

	int32 Set( cstring& key , Object& value )
	{
		iterator it = m_objects.find(key);

		int32 code = R_SUCCEED;

		if( it == m_objects.end() )
			m_objects[key] = value;
		else
		{
			code = it->second.Uninitalize();
			if( code != R_SUCCEED )
			{
				return code;
			}

			it->second = value;
		}

		return code;
	}

	int32 LoadFromString( cstring& text )
	{
		Parser textParser;
		int32 code = R_SUCCEED;

		code = textParser.Initialize( text );

		if(code != R_SUCCEED)
			return code;

		while( textParser.End() != R_SUCCEED )
		{
			string key;
			string oper;
			Object value;
			code = textParser.ReadObject( key , oper , value );
			if(code != R_SUCCEED)
				break;

			code = Set( key , value );

			if(code != R_SUCCEED)
				break;
		}

		if( code != R_SUCCEED )
			Uninitialize();

		return code;
	}

	int32 LoadFromArgument( int32 argc , tchar* argv[] )
	{
		if( argc > 1 )
		{
			string argument;
			for (int ix=1;ix<argc;++ix)
			{
				argument.append( argv[ix] );
				
				string::iterator first = argument.begin();
				string::iterator last  = argument.end();

				for(;first!=last;++first)
				{
					if(*first == _RBT('\''))
						*first = _RBT('\"');
				}

				argument.append( _RBT(" "));
			}
			return LoadFromString(argument);
		}

		return E_ARGUMENT_NULL;
	}

	int32 LoadFormFile( cstring& fileName , Encoding encoding = ENCODING_UTF8 )
	{
		int32      code   = R_SUCCEED;
		FileStream stream;

		code = stream.Open( fileName.c_str() );

		if(code != R_SUCCEED)
			return code;

		TextReader streamReader;

		code = streamReader.Initalize( &stream , encoding );

		if(code != R_SUCCEED)
			return code;

		string text;

		code = streamReader.ReadToEnd( text );

		if(code != R_SUCCEED)
			return code;

		return LoadFromString( text );
	}
};


#endif